Skip to content

Conversation

Lms24
Copy link
Member

@Lms24 Lms24 commented Aug 14, 2025

This PR updates our SvelteKit SDK to be compatible with Sveltekit's new tracing feature, while maintaining backwards compatibility with Sentry<>SvelteKit setups on previous Kit versions or when SvelteKit's tracing feature is not used.

Nothing will change for users who use SvelteKit and Sentry without builtin SvelteKit tracing support.

If Kit tracing is used, the SDK

  • No longer starts its own http.server span but uses Kit's sveltekit.handle.root span as the http.server root span.
  • Configures our httpIntegration to avoid emitting a span for the incoming request span (this is in line with NextJS and Remix)
  • Processes kit-emitted spans to include sentry op and origin in an event preprocessing integration
  • Changes the name of root span to Sentry-esque http.server name conventions
    • store original name as sveltekit.tracing.original_name attribute
  • Still isolates the request in addition

To detect at runtime, if Kit-native tracing is used, I had to make some build time adjustments

  • Read tracing config from svelte.config.js
  • Auto wrap universal load functions only for client-side code, if kit tracing is enabled
  • I also made a slight refactor of our globalValueInjection plugin which is now a standalone plugin, instead of mingled with the source maps upload plugin. Technically, this isn't necessary anymore after making more adjustments in this PR but I think it's still a good refactor, so I'd like to keep it.

Misc

  • Add tests for span processing
  • Add tests for build-time tracing config functionality
  • Add e2e test app with full tracing functionality enabled

Follow-up items to this PR

  • Better handling for remote functions. Right now, they don't produce nice traces because they're handled like non-route requests by sentryHandle. Decided to tackle this later since a) the feature is experimental and b) this PR is already too large. Sorry reviewers 😬
  • The Node adapter seems to hang when the SDK is used in instrumentation.server.ts and the server is shut down. We can fix this by listening to the process.on('sveltekit:shutdown') event.

see sveltejs/kit#13899

ref #16982

cc @elliott-with-the-longest-name-on-github

@Lms24 Lms24 changed the title ref(sveltekit): Handle SvelteKit-generated spans in sentryHandle feat(sveltekit): Add Compatibility for builtin SvelteKit Tracing Aug 25, 2025
@Lms24 Lms24 self-assigned this Aug 26, 2025
@Lms24 Lms24 force-pushed the lms/ref-sveltekit-tracing-handle-no-spans branch from c478f9d to bd930ce Compare August 26, 2025 16:29
@Lms24 Lms24 marked this pull request as ready for review August 26, 2025 16:29
Copy link
Contributor

github-actions bot commented Aug 26, 2025

size-limit report 📦

Path Size % Change Change
@sentry/browser 24.16 kB - -
@sentry/browser - with treeshaking flags 22.73 kB - -
@sentry/browser (incl. Tracing) 39.87 kB +0.01% +1 B 🔺
@sentry/browser (incl. Tracing, Replay) 78.23 kB - -
@sentry/browser (incl. Tracing, Replay) - with treeshaking flags 68.02 kB - -
@sentry/browser (incl. Tracing, Replay with Canvas) 82.91 kB +0.01% +1 B 🔺
@sentry/browser (incl. Tracing, Replay, Feedback) 95.03 kB - -
@sentry/browser (incl. Feedback) 40.83 kB - -
@sentry/browser (incl. sendFeedback) 28.81 kB - -
@sentry/browser (incl. FeedbackAsync) 33.7 kB - -
@sentry/react 25.88 kB - -
@sentry/react (incl. Tracing) 41.87 kB +0.01% +1 B 🔺
@sentry/vue 28.64 kB - -
@sentry/vue (incl. Tracing) 41.69 kB - -
@sentry/svelte 24.18 kB - -
CDN Bundle 25.66 kB +0.01% +1 B 🔺
CDN Bundle (incl. Tracing) 39.75 kB - -
CDN Bundle (incl. Tracing, Replay) 76.03 kB - -
CDN Bundle (incl. Tracing, Replay, Feedback) 81.46 kB - -
CDN Bundle - uncompressed 74.96 kB - -
CDN Bundle (incl. Tracing) - uncompressed 117.59 kB - -
CDN Bundle (incl. Tracing, Replay) - uncompressed 232.68 kB - -
CDN Bundle (incl. Tracing, Replay, Feedback) - uncompressed 245.28 kB - -
@sentry/nextjs (client) 43.89 kB - -
@sentry/sveltekit (client) 40.32 kB - -
@sentry/node-core 47.99 kB - -
@sentry/node 149.25 kB - -
@sentry/node - without tracing 92.24 kB +0.01% +1 B 🔺
@sentry/aws-serverless 104.91 kB - -

View base workflow run

@Lms24 Lms24 requested review from chargome and s1gr1d August 26, 2025 16:46
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just leaving a couple of comments!

Comment on lines 17 to 32
const defaultIntegrations = [...getDefaultNodeIntegrations(options), rewriteFramesIntegration()];

const config = getKitTracingConfig();
if (config.instrumentation) {
// Whenever `instrumentation` is enabled, we don't need httpIntegration to emit spans
// - if `tracing` is enabled, kit will emit the root span
// - if `tracing` is disabled, our handler will emit the root span
// In old (hooks.server.ts) based SDK setups, adding the default version of the integration does nothing
// for incoming requests. We still add it in default config for the undocumented case that anyone is
// using the SDK by `--import`ing the SDK setup directly (e.g. with adapter-node).
defaultIntegrations.push(httpIntegration({ disableIncomingRequestSpans: true }));
if (config.tracing) {
// If `tracing` is enabled, we need to instrument spans for the server
defaultIntegrations.push(svelteKitSpansIntegration());
}
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So this works right now but I'm not sure if it will in SvelteKit 3 when we remove the experimental flag -- we plan on keeping a flag for tracing (you probably don't want SvelteKit emitting spans / including @opentelemetry/api in your bundle if you're not planning on using it), but the instrumentation flag is going to go away entirely -- users will either create an instrumentation file or not create one, and that signals to us whether or not we need to load it. It only has a flag right now so that people have to explicitly opt into the experimental nature (in case we need to make breaking changes).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's good context, thanks Elliot!

but the instrumentation flag is going to go away entirely -- users will either create an instrumentation file or not create one

that makes sense of course. Didn't think of it but only expected the option to be lifted outside of experimental. In this case I think we can just be a bit more "naive" and avoid the conditional logic here. The only thing that will be problematic is the "undocumented" case of using the SDK with --import but not using Kit's tracing/instrumentation. Which I think we can ignore, given it's undocumented 😅

Which also means we likely don't need to inject the config at build time into the files at all 🎉 (we'll still need it at build time but for now I think that's fine).

* Experimental tracing and instrumentation config is available
* @since 2.31.0
*/
type BackwardsForwardsCompatibleKitConfig = Config['kit'] & { experimental?: SvelteKitTracingConfig };

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

love the name 😆

Copy link
Member

@chargome chargome left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice work! 🚀

if (sentryVitePluginsOptions) {
const sentryVitePlugins = await makeCustomSentryVitePlugins(sentryVitePluginsOptions);
if (mergedOptions.autoUploadSourceMaps) {
sentryPlugins.push(await makeGlobalValuesInjectionPlugin(svelteConfig, mergedOptions));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could use a comment: why is this plugin added when autoUploadSourceMaps is set

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While writing this comment, I realized we should revisit if we even have to do this. All of this frames rewriting comes from pre-debugId times. For now I decided to leave it as-is, just to not change behaviour. But left a TODO to revisit this.

*/
export function svelteKitSpansIntegration(): Integration {
return {
name: 'SvelteKitSpansEnhancment',
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
name: 'SvelteKitSpansEnhancment',
name: 'SvelteKitSpansEnhancement',

// Using preprocessEvent to ensure the processing happens before user-configured
// event processors are executed
preprocessEvent(event) {
if (event.type === 'transaction') {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As discussed we could check if the root span comes from sveltekit here.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I realized this doesn't work on cloudflare because for some reason the sveltekit.handle.root span isn't emitted.
So our Cloudflare SDK emits the http.server span. Not sure why but I think this is something to follow up on. For now I wanna get a basic, working version out.

cursor[bot]

This comment was marked as outdated.

@Lms24 Lms24 force-pushed the lms/ref-sveltekit-tracing-handle-no-spans branch from e27f7cc to 87c4109 Compare August 27, 2025 18:17
@Lms24 Lms24 merged commit e6e20d8 into develop Aug 27, 2025
162 checks passed
@Lms24 Lms24 deleted the lms/ref-sveltekit-tracing-handle-no-spans branch August 27, 2025 18:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants